package BlockingQueue;

import java.util.Arrays;
import java.util.Map;

class Do {
    public static void main(String[] args) {
        MyBlockingQueue myBlockingQueue = new MyBlockingQueue();

        Thread producer = new Thread(() -> {
            int count = 0;
            while (count <= 10) {
                try {
                    myBlockingQueue.put(count);
                    System.out.println("生产元素 : -> " + count);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                count++;
            }
        });
        Thread consumer = new Thread(() -> {
            while (true) {
                try {
                    int result = myBlockingQueue.take();
                    System.out.println("消费元素 : -> " + result);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });
        consumer.start();
        producer.start();
    }
}
public class MyBlockingQueue {
//阻塞队列可以基于数组,链表 还可以基于堆
    public int[] item = new int[5];
    public int head;
    public int tail;
    public int usedSize;
    public void put(int value) throws InterruptedException {
        //加锁的原因 : 1. 是因为多线程在进行修改操作时会产生线程不安全的问题  2. wait使用需要加锁
        synchronized (this) {
            //为什么使用while 的原因是唤醒程序之后能够判断一下时候还需要阻塞 , *官方文档的操作*
            while (usedSize == item.length) {
                //对于一个阻塞队列来说, 如果队列满了 就需要继续阻塞等待 知道队列不满
                this.wait();
            }
            item[tail++] = value;
            if(tail == item.length) tail = 0;
            usedSize++;
            this.notify();
        }
    }
    public int take() throws InterruptedException{
        synchronized (this) {
            while (usedSize == 0) {
                this.wait();
            }
            int result = item[head];
            head++;
            if(head == item.length) head = 0;
            usedSize--;
            //这里的notify如果不进行唤醒操作 对程序也不会有任何影响
            this.notify();
            return result;
        }
    }
}

